/*
 * Copyright (C) 2010 Fred Barrie This program is free software: you can
 * redistribute it and/or modify it under the terms of the GNU General Public
 * License as published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version. This program is distributed
 * in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
 * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 * See the GNU General Public License for more details. You should have received
 * a copy of the GNU General Public License along with this program. If not, see
 * <http://www.gnu.org/licenses/>.
 */
package org.aergia.vinny.main;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;
import java.util.TreeMap;
import java.util.logging.Logger;

import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;

import org.aergia.vinny.core.ApiResult;
import org.aergia.vinny.core.enums.DayOfWeek;
import org.aergia.vinny.database.Database;
import org.aergia.vinny.database.DatabaseImpl;
import org.aergia.vinny.database.pojo.Card;
import org.aergia.vinny.database.pojo.Location;
import org.aergia.vinny.database.pojo.OperatingHours;
import org.aergia.vinny.database.pojo.Organization;
import org.aergia.vinny.database.pojo.Scan;
import org.aergia.vinny.database.pojo.Skill;
import org.aergia.vinny.database.pojo.SkillRate;
import org.aergia.vinny.database.pojo.VinnyOption;
import org.aergia.vinny.database.pojo.VinnyRole;
import org.aergia.vinny.database.pojo.VinnyUser;
import org.aergia.vinny.database.pojo.Volunteer;
import org.aergia.vinny.database.pojo.VolunteerGroup;
import org.aergia.vinny.database.pojo.Workstation;
import org.aergia.vinny.engine.Engine;
import org.aergia.vinny.engine.VinnyConfiguration;
import org.aergia.vinny.util.DateUtil;
import org.aergia.vinny.util.Md5Util;

/**
 * @author fred
 */
public final class DatabaseMain {

	public static void main(final String[] args) {
		new DatabaseMain().execute();
	}

	private final VinnyConfiguration cfg;

	int counter = 0;

	private final Database database;
	private Location location;
	Logger logger;
	private Workstation workstation;

	public DatabaseMain() {
		this.cfg = new VinnyConfiguration();
		final String configurationFileName = System.getProperty("user.home") + "/.vinny/conf/cfg.xml";

		this.cfg.loadConfigurationFile(configurationFileName);

		final Map<String, Object> properties = new HashMap<String, Object>();
		properties.put("openjpa.ConnectionURL", this.cfg.getDatabaseUrl("vinny"));
		properties.put("openjpa.ConnectionUserName", this.cfg.getUserName("vinny"));
		properties.put("openjpa.ConnectionPassword", this.cfg.getUserPassword("vinny"));

		final EntityManagerFactory emf = Persistence.createEntityManagerFactory("vinny", properties);
		this.database = new DatabaseImpl(emf.createEntityManager());
		this.logger = Logger.getLogger("DatabaseMain");
	}

	public void addScan(final Volunteer volunteer, final Calendar date) {
		final Scan scan = new Scan(volunteer.getCard(), this.workstation, date);
		scan.setLocation(this.location);
		this.database.addScan(scan);
		this.logger.info(scan.toString());
	}

	private void addService(final Random random, final Volunteer volunteer, final Calendar day, final int maxStartHour, final int maxMinutes) {
		final Calendar start = DateUtil.getInstance(day);
		start.set(Calendar.HOUR_OF_DAY, random.nextInt(maxStartHour) + 5);
		start.set(Calendar.SECOND, this.counter++ % 60);
		final Calendar end = DateUtil.getInstance(start);
		final int duration = random.nextInt(maxMinutes);
		end.add(Calendar.MINUTE, duration);
		end.set(Calendar.SECOND, this.counter++ % 60);
		this.addScan(volunteer, start);
		this.addScan(volunteer, end);

		if (duration <= 5) {
			end.add(Calendar.MINUTE, random.nextInt(maxMinutes) + 5);
			this.addScan(volunteer, end);
		}

	}

	private void addVolunteer(final String firstName, final String lastName, final String cardNumber, final String groupName, final Skill skill) {
		ApiResult<VolunteerGroup> groupResult = this.database.getGroup(groupName, skill.getLocation());
		if (groupResult.isError()) {
			groupResult = this.database.addGroup(new VolunteerGroup(groupName, skill.getLocation()));
		}
		Volunteer volunteer = new Volunteer(firstName, lastName, skill);
		volunteer.setGroup(groupResult.getResult());
		final ApiResult<Volunteer> result = this.database.addVolunteer(volunteer);
		volunteer = result.getResult();
		final Card card = new Card(cardNumber, volunteer, DateUtil.getInstance());
		this.database.addCard(card);
		volunteer.setCard(card);
		this.database.saveVolunteer(volunteer);
	}

	public void execute() {

		if (!this.database.isInitialized()) {
			this.initializeLocation();
		} else {
			final ApiResult<Skill> result = this.database.getSkill(Skill.GENERAL_SKILL);
			this.addVolunteer("Fred", "B.", "0001022", "Programmers", result.getResult());
			this.addVolunteer("Jo Ella", "B.", "0001026", "NV Volunteers", result.getResult());
			this.addVolunteer("Janet", "W.", "0001027", "NV Volunteers", result.getResult());
			this.addVolunteer("Krista", "L.", "0001020", VolunteerGroup.GENERAL_GROUP, result.getResult());
			this.addVolunteer("Lindsey", "B.", "0001028", "NV Volunteers", result.getResult());

			this.addVolunteer("Frank", "L.", "0001001", VolunteerGroup.GENERAL_GROUP, result.getResult());
			this.addVolunteer("James", "X.", "0001002", VolunteerGroup.GENERAL_GROUP, result.getResult());
			this.addVolunteer("Kathy", "A.", "0001003", VolunteerGroup.GENERAL_GROUP, result.getResult());
			this.addVolunteer("Kathy", "B.", "0001004", VolunteerGroup.GENERAL_GROUP, result.getResult());
			this.addVolunteer("Tori", "F.", "0001005", VolunteerGroup.GENERAL_GROUP, result.getResult());
			this.addVolunteer("Dawn", "E.", "0001006", VolunteerGroup.GENERAL_GROUP, result.getResult());
			this.addVolunteer("Maria", "P.", "0001007", VolunteerGroup.GENERAL_GROUP, result.getResult());
			this.addVolunteer("Maria", "B.", "0001008", VolunteerGroup.GENERAL_GROUP, result.getResult());
			this.addVolunteer("Tammy", "C.", "0001009", VolunteerGroup.GENERAL_GROUP, result.getResult());

		}

		this.location = this.database.getLocation(this.cfg.getLocationId("vinny")).getResult();

		if (this.location == null) {
			System.out.println("Error location is NULL");
			System.exit(-1);
		}

		final Random random = new Random();
		final Collection<? extends Volunteer> volunteers = this.database.getVolunteers();

		final Calendar date = Calendar.getInstance();
		date.set(Calendar.YEAR, 2011);
		date.set(Calendar.MONTH, Calendar.JANUARY);
		date.set(Calendar.DAY_OF_MONTH, 1);

		while (Calendar.getInstance().after(date)) {
			for (final Volunteer volunteer : volunteers) {
				final int rand = random.nextInt(10);
				if (rand == 0) {
					this.addService(random, volunteer, date, 15, 120);
				}
				if (rand == 1) {
					this.addService(random, volunteer, date, 5, 480);
					this.addService(random, volunteer, date, 11, 240);
				}
			}
			date.add(Calendar.DAY_OF_MONTH, 1);
		}
	}

	private int initializeLocation() {
		final String orgName = "Organization";
		final String locName = "Location";
		final Organization org = new Organization(orgName);
		this.database.addOrganization(org);
		this.location = new Location(locName, org);
		this.database.addLocation(this.location);

		// MONDAY
		OperatingHours hours = new OperatingHours(DayOfWeek.MONDAY, 7 * 60, 16 * 60);
		hours.setLocation(this.location);
		this.database.addOperatingHours(hours);

		// TUESDAY
		hours = new OperatingHours(DayOfWeek.TUESDAY, 7 * 60, 17 * 60);
		hours.setLocation(this.location);
		this.database.addOperatingHours(hours);

		// WEDNESDAY
		hours = new OperatingHours(DayOfWeek.WEDNESDAY, 7 * 60, 18 * 60);
		hours.setLocation(this.location);
		this.database.addOperatingHours(hours);

		// THURSDAY
		hours = new OperatingHours(DayOfWeek.THURSDAY, 7 * 60, 19 * 60);
		hours.setLocation(this.location);
		this.database.addOperatingHours(hours);

		// FRIDAY
		hours = new OperatingHours(DayOfWeek.FRIDAY, 7 * 60, 20 * 60);
		hours.setLocation(this.location);
		this.database.addOperatingHours(hours);

		// SATURDAY
		hours = new OperatingHours(DayOfWeek.SATURDAY, 12 * 60, 20 * 60);
		hours.setLocation(this.location);
		this.database.addOperatingHours(hours);

		final Collection<VinnyRole> vinnyRoles = new ArrayList<VinnyRole>();
		final String[] roles = { VinnyRole.MODIFY_CONFIGURATION, VinnyRole.MODIFY_SERVICE, VinnyRole.MODIFY_USER, VinnyRole.MODIFY_VOLUNTEER };
		for (final String role : roles) {
			final VinnyRole vinnyRole = new VinnyRole(role);
			final ApiResult<VinnyRole> roleResult = this.database.addRole(vinnyRole);
			if (roleResult.isError()) {
				this.logger.severe(roleResult.getText());
			}
			vinnyRoles.add(roleResult.getResult());
		}

		final VinnyUser admin = new VinnyUser("admin");
		admin.setRoles(vinnyRoles);
		admin.setPassword(Md5Util.encode("password"));
		admin.setLocation(this.location);
		final ApiResult<VinnyUser> userResult = this.database.addUser(admin);
		if (userResult.isError()) {
			this.logger.severe(userResult.getText());
		}

		final Skill skill = new Skill(Skill.GENERAL_SKILL);
		skill.setLocation(this.location);
		this.database.addSkill(skill);

		final SkillRate skillRate = new SkillRate(skill, 2085, DateUtil.getInstance());
		this.database.addSkillRate(skillRate);

		final VolunteerGroup group = new VolunteerGroup(VolunteerGroup.GENERAL_GROUP, this.location);
		final ApiResult<VolunteerGroup> groupResult = this.database.addGroup(group);
		if (groupResult.isError()) {
			this.logger.severe(groupResult.getText());
		}

		final Map<String, String> options = new TreeMap<String, String>();
		options.put(VinnyOption.PRODUCT_NAME, Engine.DEFAULT_PRODUCT_NAME);
		options.put(VinnyOption.AUTO_AUTHORIZE, "true");
		options.put(VinnyOption.MINIMUM_SERVICE_TIME, "5");
		options.put(VinnyOption.ICON_FILE_NAME, "images/256/trackin_it.png");
		options.put(VinnyOption.DISPLAY_SERVICE_TYPES, "false");
		options.put(VinnyOption.USE_OPERATING_HOURS, "true");
		options.put(VinnyOption.FIRST_MONTH_OF_YEAR, "Jan");
		options.put(VinnyOption.DISPLAY_SERVICE_TYPES, "300");

		for (final String optionName : options.keySet()) {
			final VinnyOption option = new VinnyOption(optionName, options.get(optionName), this.location);
			this.database.setOption(option);
		}

		this.addVolunteer("Fred", "B.", "0001022", "Programmers", skill);
		this.addVolunteer("Jo Ella", "B.", "0001026", "NV Volunteers", skill);
		this.addVolunteer("Janet", "W.", "0001027", "NV Volunteers", skill);
		this.addVolunteer("Krista", "L.", "0001020", VolunteerGroup.GENERAL_GROUP, skill);
		this.addVolunteer("Lindsey", "B.", "0001028", "NV Volunteers", skill);

		this.addVolunteer("Frank", "L.", "0001001", VolunteerGroup.GENERAL_GROUP, skill);
		this.addVolunteer("James", "X.", "0001002", VolunteerGroup.GENERAL_GROUP, skill);
		this.addVolunteer("Kathy", "A.", "0001003", VolunteerGroup.GENERAL_GROUP, skill);
		this.addVolunteer("Kathy", "B.", "0001004", VolunteerGroup.GENERAL_GROUP, skill);
		this.addVolunteer("Tori", "F.", "0001005", VolunteerGroup.GENERAL_GROUP, skill);
		this.addVolunteer("Dawn", "E.", "0001006", VolunteerGroup.GENERAL_GROUP, skill);
		this.addVolunteer("Maria", "P.", "0001007", VolunteerGroup.GENERAL_GROUP, skill);
		this.addVolunteer("Maria", "B.", "0001008", VolunteerGroup.GENERAL_GROUP, skill);
		this.addVolunteer("Tammy", "C.", "0001009", VolunteerGroup.GENERAL_GROUP, skill);

		this.workstation = new Workstation("workstation", this.location);
		this.database.addWorkstation(this.workstation);

		return 0;
	}
}
